package com.hualan.sfzyproject.handler;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hualan.sfzyproject.domain.ChatMessageDTO;
import com.hualan.sfzyproject.service.ChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 处理WebSocket消息的组件
 * 用于管理聊天系统的WebSocket连接和消息分发
 */
@Component
@Slf4j
public class ChatWebSocketHandler extends TextWebSocketHandler {
    // 存储所有当前活跃的WebSocket会话，键为用户ID，值为会话对象
    private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
    // 用于序列化和反序列化JSON对象
    @Autowired
    private ObjectMapper objectMapper;

    // 聊天服务接口，用于处理消息的保存等业务逻辑
    @Autowired
    private ChatService chatService;

    /**
     * 处理接收到的文本消息
     *
     * @param session 当前消息的会话
     * @param message 接收到的消息对象
     * @throws Exception 如果消息处理过程中发生错误
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        try {
            log.info("收到消息: {}", message.getPayload());
            // 将接收到的消息内容反序列化为Map对象
            Map<String, Object> messageMap = objectMapper.readValue(
                    message.getPayload(),
                    new TypeReference<Map<String, Object>>() {}
            );

            // 验证消息格式是否正确
            if (!validateMessage(messageMap)) {
                log.error("消息格式不正确: {}", messageMap);
                return;
            }
            // 保存消息到数据库
            chatService.saveMessage(messageMap);
            // 获取接收者ID
            String receiverId = String.valueOf(messageMap.get("receiverId"));
            String type = String.valueOf(messageMap.get("type"));
            // 判断消息来源，并根据消息来源进行转发
            boolean isMiniProgram = type.startsWith("wx");
            System.out.println(isMiniProgram);
            // 根据接收者类型发送消息
            if (isMiniProgram) {
                // 发送给Vue端的消息格式
                sendMessageToConsultant(receiverId, messageMap);
            } else {
                // 发送给小程序的消息格式
                sendMessageToMiniProgram(receiverId, messageMap);
            }
        } catch (Exception e) {
            log.error("处理消息时发生错误", e);
            // 发送错误消息给客户端
            sendErrorMessage(session, "消息处理失败");
        }
    }

    /**
     * 发送消息给小程序用户
     *
     * @param receiverId 接收者ID
     * @param message 消息内容
     */
    private void sendMessageToMiniProgram(String receiverId, Map<String, Object> message) {
        WebSocketSession session = sessions.get(receiverId);
        if (session != null && session.isOpen()) {
            try {
                // 构建小程序需要的消息格式
                Map<String, Object> miniProgramMessage = new HashMap<>();
                miniProgramMessage.put("senderId", message.get("senderId"));
                miniProgramMessage.put("senderName", message.get("senderName"));
                miniProgramMessage.put("senderAvatar", message.get("senderAvatar"));
                miniProgramMessage.put("content", message.get("content"));
                miniProgramMessage.put("timestamp", message.get("timestamp"));
                miniProgramMessage.put("type", "vue");  // 标记消息来源
                
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(miniProgramMessage)));
                log.info("成功发送消息到小程序: {}", miniProgramMessage);
            } catch (Exception e) {
                log.error("发送消息到小程序失败: {}", e.getMessage());
            }
        } else {
            // 添加日志，记录接收者不在线的情况
            log.warn("接收者 {} 不在线或连接已关闭", receiverId);
        }
    }

    /**
     * 发送消息给Vue端用户
     *
     * @param consultantId 接收者ID
     * @param message 消息内容
     */
    private void sendMessageToConsultant(String consultantId, Map<String, Object> message) {
        WebSocketSession session = sessions.get(consultantId);
        if (session != null && session.isOpen()) {
            try {
                // 构建Vue端需要的消息格式
                Map<String, Object> response = new HashMap<>();
                response.put("code", 200);
                
                Map<String, Object> messageData = new HashMap<>();
                messageData.put("senderId", message.get("senderId"));
                messageData.put("senderName", message.get("senderName"));
                messageData.put("content", message.get("content"));
                messageData.put("timestamp", message.get("timestamp"));
                messageData.put("senderAvatar", message.get("senderAvatar"));
                messageData.put("type", "miniprogram");  // 标记消息来源
                
                response.put("data", messageData);
                
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                log.info("成功发送消息到Vue端: {}", response);
            } catch (Exception e) {
                log.error("发送消息到Vue端失败: {}", e.getMessage());
            }
        }
    }

    /**
     * 发送错误消息给客户端
     *
     * @param session 当前消息的会话
     * @param errorMessage 错误消息内容
     */
    private void sendErrorMessage(WebSocketSession session, String errorMessage) {
        try {
            // 构建错误消息格式
            Map<String, Object> error = new HashMap<>();
            error.put("code", 500);
            error.put("message", errorMessage);

            // 发送消息
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(error)));
        } catch (Exception e) {
            log.error("发送错误消息失败", e);
        }
    }

    /**
     * 验证消息格式是否正确
     *
     * @param message 消息内容
     * @return 如果消息格式正确返回true，否则返回false
     */
    private boolean validateMessage(Map<String, Object> message) {
        // 检查消息是否包含必要的字段
        return message != null
                && message.get("senderId") != null
                && message.get("receiverId") != null
                && message.get("content") != null;
    }

    /**
     * 在WebSocket连接建立后调用
     *
     * @param session 当前消息的会话
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        // 提取用户ID并存储会话
        String userId = extractUserId(session);
        // 提取用户ID
        if (userId != null) {
            sessions.put(userId, session);
            log.info("用户 {} 已连接, 当前在线用户: {}", userId, sessions.keySet());
        }
    }

    /**
     * 提取WebSocket会话中的用户ID
     *
     * @param session 当前消息的会话
     * @return 用户ID，如果提取失败返回null
     */
    private String extractUserId(WebSocketSession session) {
        try {
            String query = session.getUri().getQuery();
            if (query != null && query.contains("userId=")) {
                return query.split("userId=")[1];
            }
        } catch (Exception e) {
            log.error("提取用户ID失败", e);
        }
        return null;
    }

    /**
     * 在WebSocket连接关闭后调用
     *
     * @param session 当前消息的会话
     * @param status 连接关闭的状态
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        // 移除断开连接的用户会话
        String userId = session.getUri().getQuery().split("=")[1];
        sessions.remove(userId);
        log.info("用户 {} 已断开连接", userId);
    }
}
